package cn.com.cfae.iras.doc.analyze.parse.tokenizer;

import cn.com.cfae.iras.doc.analyze.parse.RegexUtil;
import cn.com.cfae.iras.doc.analyze.parse.kv.KVText;
import cn.com.cfae.iras.doc.analyze.parse.kv.TextLayout;
import cn.com.cfae.iras.doc.analyze.parse.model.*;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.hankcs.hanlp.HanLP;
import com.hankcs.hanlp.corpus.document.sentence.Sentence;
import com.hankcs.hanlp.corpus.document.sentence.word.IWord;
import com.hankcs.hanlp.corpus.io.FileIOAdapter;
import com.hankcs.hanlp.dictionary.stopword.CoreStopWordDictionary;
import com.hankcs.hanlp.dictionary.stopword.StopWordDictionary;
import com.hankcs.hanlp.tokenizer.NLPTokenizer;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Mac;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ZCFZTokenizer extends BaseTokenizer {

    private static ZCFZTokenizer instance = new ZCFZTokenizer();


    public static ZCFZTokenizer getInstance() {
        return instance;
    }

    private ZCFZTokenizer() {
    }

    private static Logger logger = LoggerFactory.getLogger(ZCFZTokenizer.class);

    private List<String> getYears(KJKMItem kjkmItem) {
        List<String> yearList = new ArrayList<>();
        String regex = "(年至|-)";
        for (int i = 0; i < kjkmItem.getDateList().size(); i++) {
            WordItem wordItem = kjkmItem.getDateList().get(i);
            Pattern pattern = Pattern.compile(CWBB_NB_FORMAT);
            Matcher matcher = pattern.matcher(wordItem.getValue());
            if (matcher.matches()) {
                pattern = Pattern.compile(regex);
                matcher = pattern.matcher(wordItem.getValue());
                if (matcher.find()) {
                    String[] splits = wordItem.getValue().split(matcher.group());
                    int start = Integer.parseInt(getRegexUtil().extractZCFZ_NB_WITH_YEAR(splits[0].trim()));
                    int end = Integer.parseInt(getRegexUtil().extractZCFZ_NB_WITH_YEAR(splits[1].trim()));
                    for (int j = start; j <= end; j++) {
                        if (!yearList.contains(String.valueOf(j))) {
                            yearList.add(String.valueOf(j));
                        }
                    }
                }
            }
            pattern = Pattern.compile(CWBB_JB_FORMAT);
            matcher = pattern.matcher(wordItem.getValue());
            if (matcher.matches()) {
                if (yearList.size() >= 4) {
                    break;
                }
                String year = getRegexUtil().extractZCFZ_JB_WITH_YEAR(wordItem.getValue());
                if (!yearList.contains(year)) {
                    yearList.add(year);
                }
            }
            pattern = Pattern.compile(CWBB_JSNJYQ_FORMAT);
            matcher = pattern.matcher(wordItem.getValue());
            if (matcher.matches()) {
                yearList.addAll(Arrays.asList(getYears()));
                break;
            }
        }
        return yearList;
    }


    /**
     * 抽取M2章节会计科目风险分析
     *
     * @param extractBizModel
     * @param
     */
    public void splitWords5(ExtractBizModel extractBizModel, SectionModel childSectionModel) {
        logger.info("开始进行财务报表会计科目分析，表格类型：{}......", extractBizModel.getModelName());
        long t1 = System.currentTimeMillis();
        String text = childSectionModel.getContent();
        Sentence sentence = NLPTokenizer.ANALYZER.analyze(text);
        ExtractItem extractItem = null;
        List<IWord> wordList = sentence.wordList;
        IWord iWord = null;
        Map<String, ExtractItem> extractItemMap = new HashMap<>();
        logger.info("分析财务报表会计科目，表格类型：{}，文本：{}，列表：{}。", extractBizModel.getModelName(), text, wordList);
        int offset = -1;
        for (int i = 0; i < wordList.size(); i++) {
            iWord = wordList.get(i);
            String word = iWord.getValue();
            if (extractBizModel.getSynonyms().contains(word)) {
                offset = i;
                extractItem = extractBizModel.getExtractItemBySynonym(word);
                if (extractItem == null) {
                    continue;
                }
                if (!extractItemMap.containsKey(extractItem.getItemName())) {
                    extractItemMap.put(extractItem.getItemName(), extractItem);
                    extractItem.setItemValue(iWord.getValue());
                    logger.info("分析到财务报表会计科目，报表类型：{}，科目名称：{}，ItemName：{}，索引位置：{}。", extractBizModel.getModelName(), word, extractItem.getItemName(), offset);
//                    continue;
                    //TODO 会计科目分析会出现多个名称，如何进一步识别正确的会计科目，后续还需通过统计词频来分析判断
                    break;
                }
            }
        }
        if (offset < 0) {
            return;
        }
        List<WordItem> wordItemList = null;
        for (Iterator<String> it = extractItemMap.keySet().iterator(); it.hasNext(); ) {
            wordItemList = new ArrayList<>();
            String key = it.next();
            ExtractItem var1 = extractItemMap.get(key);
//            String prefixRegex = "((近三年及一期)|(近三年又一期)(20\\d{2}\\s{0,}(年至)\\s{0,}20\\d{2}\\s{0,}[年]{1})|(20\\d{2}\\-{1}20\\d{2}\\s{0,}[年]{1}){1}|(20\\d{2}\\s{0,}年\\s{0,}\\d{1,2}\\-{0,1}\\d{0,2}\\s{0,}月){1}|(" + var1.getItemValue() +
//                    "){1})";
//            String prefixRegex = "((近三年及一期)|(近三年又一期)|(20\\d{2}\\s{0,}年至\\s{0,}20\\d{2}\\s{0,}年)|(20\\d{2}\\-{1}20\\d{2}\\s{0,}[年]{1})|(20\\d{2}\\s{0,}年\\s{0,}\\d{1,2}\\-{0,1}\\d{0,2}\\s{0,}月){1}|(投资活动产生的现金流出量){1})";
////            String suffixRegex = "((([0-9]{0,3}\\,{0,}){0,}([0-9]{1,3}){1,}\\.{0,}[0-9]{2})\\s{0,}(亿元|万元){1})";
//            String suffixRegex = "((([0-9]{0,3}\\,{1,}){0,}([0-9]{1,3}){1,}\\.{0,}[0-9]{0,2})\\s{0,}(亿元|万元){1})";
//            String prefixRegex = "((近三年及一期)|(近三年又一期)|(截止\\s{0,}20\\d{2}\\s{0,}年末)|(20\\d{2}\\s{0,}年至\\s{0,}20\\d{2}\\s{0,}年)|(20\\d{2}\\s{0,}[年]{1}\\-{1}20\\d{2}\\s{0,}[年]{1})|(20\\d{2}\\-{1}20\\d{2}\\s{0,}[年]{1})|(20\\d{2}\\s{0,}年\\s{0,}\\d{1,2}\\-{0,1}\\d{0,2}\\s{0,}月){1}|(" + var1.getItemValue() + "){1})";
            String prefixRegex = "((近三年及一期)|(近三年又一期)|(20\\d{2}\\s{0,}年[一二三四]季度)|(截止\\s{0,}20\\d{2}\\s{0,}年末)|(20\\d{2}\\s{0,}年至\\s{0,}20\\d{2}\\s{0,}年)|(20\\d{2}\\s{0,}[年]{1}\\-{1}20\\d{2}\\s{0,}[年]{1})|(20\\d{2}\\-{1}20\\d{2}\\s{0,}[年]{1})|(20\\d{2}\\s{0,}年\\s{0,}\\d{1,2}\\-{0,1}\\d{0,2}\\s{0,}月){1}|(" + var1.getItemValue() + "){1})";
            String suffixRegex = "((\\-?([0-9]{0,3}\\,{1,}){0,}([0-9]{1,3}){1,}\\.{0,}[0-9]{0,2})\\s{0,}(亿元|万元){1})";
            Pattern pattern = Pattern.compile(prefixRegex);
            Matcher matcher = pattern.matcher(text);
            WordItem wordItem;
            while (matcher.find()) {
                wordItem = new WordItem();
                wordItem.setValue(matcher.group());
                wordItem.setOffset(matcher.start());
                wordItemList.add(wordItem);
            }

            pattern = Pattern.compile(suffixRegex);
            matcher = pattern.matcher(text);
            while (matcher.find()) {
                wordItem = new WordItem();
                wordItem.setValue(matcher.group());
                wordItem.setOffset(matcher.start());
                wordItemList.add(wordItem);
            }
            Collections.sort(wordItemList);
            logger.info("抽取财务报表，表格类型：{}，输出提取的业务指标内容，extractItem：{}，指标名称：{}。", extractBizModel.getModelName(), var1.getItemName(), var1.getItemValue());
            wordItemList.forEach(e -> {
                logger.info("抽取财务报表，表格类型：{}，抽取到会计科目相关信息，分析文本：{}，偏移位置：{}。", extractBizModel.getModelName(), e.getValue(), e.getOffset());
            });
            boolean isSkip = false;
            KJKMItem kjkmItem = new KJKMItem();
            for (int i = 0; i < wordItemList.size(); i++) {
                wordItem = wordItemList.get(i);
                if (isYearFormat(wordItem.getValue())) {
                    kjkmItem.addPrefix(wordItem);
                }
                if (ArrayUtils.contains(var1.getSynonyms(), wordItem.getValue())) {
                    List<WordItem> dateWordItemList = kjkmItem.getDateList();
                    for (WordItem dateWordItem : dateWordItemList) {
                        if (wordItem.getOffset() - dateWordItem.getOffset() > 100) {
                            isSkip = true;
                            break;
                        }
                    }
                    if (isSkip) {
                        break;
                    }
                    kjkmItem.addWordItem(wordItem);
                }

                if (isAmt(wordItem.getValue())) {
                    if (kjkmItem.getDateList().size() <= 0) {
                        continue;
                    }
                    if (kjkmItem.getAmtList().size() >= 4) {
                        break;
                    }
                    if (kjkmItem.getWordItem() != null) {
                        if (kjkmItem.getWordItem().getOffset() < wordItem.getOffset()) {
                            kjkmItem.addAmt(wordItem);
                        }
                    }
                }
            }
            if (kjkmItem.getAmtList().isEmpty()) {
                continue;
            }
            List<String> yearList = getYears(kjkmItem);
            if (yearList.isEmpty()) {
                continue;
            }
            for (int i = 0; i < yearList.size(); i++) {
                try {
                    ExtractItem newExtractItem = (ExtractItem) BeanUtils.cloneBean(var1);
                    KVText kText = new KVText();
                    TextLayout kTextLayout = new TextLayout();
                    TextLayout vTextLayout = new TextLayout();
                    kTextLayout.setTop(childSectionModel.getTextLayout().getTop());
                    kTextLayout.setLeft(childSectionModel.getTextLayout().getLeft());
                    kTextLayout.setWidth(childSectionModel.getTextLayout().getWidth());
                    kTextLayout.setHeight(childSectionModel.getTextLayout().getHeight());
                    vTextLayout.setTop(childSectionModel.getTextLayout().getTop());
                    vTextLayout.setLeft(childSectionModel.getTextLayout().getLeft());
                    vTextLayout.setWidth(childSectionModel.getTextLayout().getWidth());
                    vTextLayout.setHeight(childSectionModel.getTextLayout().getHeight());
                    kText.setText(newExtractItem.getSynonyms()[0]);
                    KVText vText = new KVText();
                    kText.add(childSectionModel.getTextLayout());
                    vText.add(childSectionModel.getTextLayout());
                    vText.setText(kjkmItem.getAmtList().get(i).getValue());
                    vTextLayout.setText(vText.getText());
                    newExtractItem.setKey(kText);
                    newExtractItem.setValue(vText);
                    if (extractBizModel.getTable(yearList.get(i)) == null) {
                        extractBizModel.addTable(yearList.get(i));
                    }
                    if (!extractBizModel.getTable(yearList.get(i)).containsKey(extractItem.getItemName())) {
                        extractBizModel.getTable(yearList.get(i)).put(newExtractItem.getItemName(), newExtractItem);
                    }
                } catch (IllegalAccessException e) {
                    logger.error(e.getMessage(), e);
                } catch (InstantiationException e) {
                    logger.error(e.getMessage(), e);
                } catch (InvocationTargetException e) {
                    logger.error(e.getMessage(), e);
                } catch (NoSuchMethodException e) {
                    logger.error(e.getMessage(), e);
                }
            }
        }
        long t2 = System.currentTimeMillis();
        logger.info("资产负债表会计科目分资产负债表会计科目分析完成析完成，耗时：{}毫秒。", (t2 - t1));
    }

    public void splitWords(ExtractBizModel extractBizModel, String text) {
        logger.info("开始进行资产负债表会计科目分析......");
        long t1 = System.currentTimeMillis();
        Sentence sentence = NLPTokenizer.ANALYZER.analyze(text);
        ExtractItem extractItem = null;
        List<IWord> wordList = sentence.wordList;
        IWord iWord = null;
        IWord targetIWord = null;
        logger.info("分析资产负债表会计科目，文本：{}，列表：{}。", text, wordList);
        int offset = -1;
        for (int i = 0; i < wordList.size(); i++) {
            iWord = wordList.get(i);
            String word = iWord.getValue();
            if (extractBizModel.getSynonyms().contains(word)) {
                offset = i;
                targetIWord = iWord;
                extractItem = extractBizModel.getExtractItemBySynonym(word);
                logger.info("解析到资产负债表会计科目，科目名称：{}，ItemName：{}，索引位置：{}。", word, extractItem.getItemName(), offset);
                break;
            }
        }

        logger.info("抽取资产负债表相关会计科目，开始分析上文......");
        for (int i = 0; i < offset; i++) {
            iWord = wordList.get(i);
            if (isJSNJYQ(iWord.getValue())) {
                //TODO 后续加逻辑
                logger.info("解析到近三年及一期，添加Key值：{}。", Arrays.asList(getYears()));
                for (String year : getYears()) {
                    extractBizModel.addTable(year);
                }
                break;
            }
        }
        logger.info("抽取资产负债表，分析上文完成。");
        List<String> amtList = new ArrayList<String>();
        if (offset == -1) {
            return;
        }
        logger.info("抽取资产负债相关会计科目，开始分析下文......");
        for (int i = offset; i < wordList.size(); i++) {
            iWord = wordList.get(i);
            if (isZCFZ_JE(iWord.getValue().trim())) {
                logger.info("分析到对应金额：{}。", iWord.getValue());
                amtList.add(iWord.getValue());
            }
            if (amtList.size() == 4) {
                break;
            }
        }
        logger.info("抽取资产负债表，分析下文完成。");
        String[] years = getYears();
        for (int i = 0; i < amtList.size(); i++) {
            try {
                ExtractItem extractItem1 = (ExtractItem) BeanUtils.cloneBean(extractItem);
                KVText key = new KVText();
                key.setText(extractItem1.getSynonyms()[0]);
                KVText value = new KVText();
                value.setText(amtList.get(i));
                extractItem1.setKey(key);
                extractItem1.setValue(value);
                extractBizModel.getTable(years[i]).put(extractItem1.getItemName(), extractItem1);
            } catch (IllegalAccessException e) {
                logger.error(e.getMessage(), e);
            } catch (InstantiationException e) {
                logger.error(e.getMessage(), e);
            } catch (InvocationTargetException e) {
                logger.error(e.getMessage(), e);
            } catch (NoSuchMethodException e) {
                logger.error(e.getMessage(), e);
            }
        }
        long t2 = System.currentTimeMillis();
        logger.info("资产负债表会计科目分析完成，耗时：{}毫秒。", (t2 - t1));
    }

    /**
     * 用于资产负债表、利润表、现金流量表数据抽取，最后切词提取
     *
     * @param extractBizModel
     * @param text
     * @return
     */
    public ExtractItem splitWords3(ExtractBizModel extractBizModel, String text) {
        long t1 = System.currentTimeMillis();
        logger.info("开始分析{}表会计科目......", extractBizModel.getModelName());
        Sentence sentence = NLPTokenizer.ANALYZER.analyze(text);
        ExtractItem extractItem = null;
        List<IWord> wordList = sentence.wordList;
        IWord iWord = null;
        logger.info("分析{}表会计科目，分析文本：{}，分词列表：{}。", extractBizModel.getModelName(), text, wordList);
        int offset = -1;
        for (int i = 0; i < wordList.size(); i++) {
            iWord = wordList.get(i);
            String word = iWord.getValue();
            if (extractBizModel.getSynonyms().contains(word)) {
                offset = i;
                extractItem = extractBizModel.getExtractItemBySynonym(word);
                logger.info("分析到到{}表会计科目，ItemName：{}，会计科目名称：{}，索引位置：{}。", extractBizModel.getModelName(), extractItem.getItemName(), word, offset);
                break;
            }
        }
        long t2 = System.currentTimeMillis();
        logger.info("分析{}表会计科目完成，耗时：{}毫秒。", extractBizModel.getModelName(), (t2 - t1));
        return extractItem;
    }

    private String[] getYears() {
        return new String[]{"2015", "2016", "2017", "2018"};
    }
}
